package com.lagou.edu.spring.web;

import com.lagou.edu.spring.core.ApplicationContext;
import com.lagou.edu.spring.core.BeanDefinition;
import com.lagou.edu.spring.core.impl.AnnotationConfigApplicationContext;
import com.lagou.edu.spring.core.impl.XmlConfigApplicationContext;
import com.lagou.edu.spring.exceptions.MySpringException;
import com.lagou.edu.spring.mybatis.MapperBeanParseProcess;
import com.lagou.niancheng.core.parse.Resources;
import com.lagou.niancheng.core.session.SqlSessionFactory;
import com.lagou.niancheng.core.session.SqlSessionFactoryBuilder;
import org.dom4j.DocumentException;

import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import java.beans.PropertyVetoException;
import java.util.List;

/**
 * web工程接入my-spring的监听器
 *
 * @author 大犬
 * @date 2020/4/2
 */
public class MySpringWebListener implements ServletContextListener {

    private ApplicationContext applicationContext;

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        String configType = servletContextEvent.getServletContext().getInitParameter("configType");
        if (configType == null) {
            throw new MySpringException("configType cannot be null");
        }
        // TODO：1.创建容器
        // 获取配置方式创建不同的容器
        WebConfigTypeEnum configTypeEnum = WebConfigTypeEnum.getByValue(configType);
        switch (configTypeEnum) {
            case CONFIG_FILE:
                // 使用配置文件创建容器
                applicationContext = createApplicationContextByConfigFile(servletContextEvent.getServletContext());
                break;
            case CONFIG_CLASS:
                // 使用配置类创建容器
                applicationContext = createApplicationContextByConfigClass(servletContextEvent.getServletContext());
                break;
            case CONFIG_PACKAGE:
                // 使用包路径创建容器
                applicationContext = createApplicationContextByConfigPackage(servletContextEvent.getServletContext());
                break;
            default:
                throw new MySpringException("not supported configType:" + configType);
        }
        // 注入MySpringWebServletProcessor处理器到容器中
        injectionMySpringWebServletProcessor(applicationContext, servletContextEvent.getServletContext());
        // 容器初始化
        // TODO：2.容器进入初始化
        applicationContext.refresh();
        // 把容器中的所有servlet拿出来交给web容器
        addSpringWebServlet(servletContextEvent.getServletContext());
    }


    private void addSpringWebServlet(ServletContext servletContext) {
        // 获取容器中所有Servlet，并将这些servlet接给web容器
        List<Servlet> servletList = applicationContext.getBeans(Servlet.class);
        for (Servlet servlet : servletList) {
            Class<? extends Servlet> aClass = servlet.getClass();
            MySpringWebServlet webServlet = aClass.getAnnotation(MySpringWebServlet.class);
            if (webServlet != null) {
                String name = webServlet.servletName();
                if (name.isEmpty()) {
                    name = aClass.getSimpleName();
                }
                ServletRegistration.Dynamic dynamic = servletContext.addServlet(name, servlet);
                dynamic.addMapping(webServlet.pattern());
            }
        }
    }

    private ApplicationContext createApplicationContextByConfigPackage(ServletContext servletContext) {
        String configPackage = servletContext.getInitParameter("configPackage");
        if (configPackage == null) {
            throw new MySpringException("configPackage cannot be null");
        }
        // TODO：作业审核直接看这里
        return new AnnotationConfigApplicationContext(configPackage);
    }

    private ApplicationContext createApplicationContextByConfigClass(ServletContext servletContext) {
        String configClass = servletContext.getInitParameter("configClass");
        if (configClass == null) {
            throw new MySpringException("configClass cannot be null");
        }
        try {
            Class<?> aClass = Class.forName(configClass);
            return new AnnotationConfigApplicationContext(aClass);
        } catch (ClassNotFoundException e) {
            throw new MySpringException("load configClass failed", e);
        }
    }

    private ApplicationContext createApplicationContextByConfigFile(ServletContext servletContext) {
        String configFile = servletContext.getInitParameter("configFile");
        if (configFile == null) {
            throw new MySpringException("configFile cannot be null");
        }
        return new XmlConfigApplicationContext(configFile);
    }

    private void injectionMySpringWebServletProcessor(ApplicationContext applicationContext, ServletContext servletContext) {
        // 给webServlet设置servletContext依赖
        MySpringWebServletProcessor.setServletContext(servletContext);
        // 注入webServlet注解解析器
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanType(MySpringWebServletProcessor.class);
        applicationContext.registerBeanDefinition("MySpringWebServletProcessor", beanDefinition);
    }


    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        // 容器关闭
        applicationContext.close();
    }
}
